package com.mxprojects.constructors
{
	import com.mxprojects.gui.Styles;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.MouseEvent;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	
	public class InputConstructor extends Sprite
	{
		public static const LABEL_SEPARATOR:String = ": ";
		
		private const LABEL_NAME:String = "label";
		private const INPUT_NAME:String = "input";
		private const BACKGROUND_NAME:String = "background";
		private const SCROLLER_NAME:String = "scroller";
		//private const RESTRICT_CHARACTERS:String = "A-Za-z0-9";
		private const INDENT_AMOUNT:int = 2;
		
		public var inputLabel:SimpleTextField;
		public var inputBox:TextField;
		public var inputBoxBackground:Sprite;
		public var scroller:TextScroller;
		
		private var rows:int;
		private var labelStyleCSS:String;
		private var inputStyleCSS:String;
		private var inputDisabledCSS:String;
		
		public function InputConstructor(labelString:String, prePopulatedText:String = "", tabIndex:uint = 1, 
										 isPassword:Boolean = false, rows:uint = 1, labelStyleCSS:String = "formInputLabel", 
										 inputStyleCSS:String = "formInput", maxChars:uint = 0, restrictInput:String = "", 
										 isEditable:Boolean = true, inputDisabledCSS:String = "formDisabled"){
			
			//set the local CSS vars
			this.labelStyleCSS = labelStyleCSS;
			this.inputStyleCSS = inputStyleCSS;
			this.inputDisabledCSS = inputDisabledCSS;		
			
			//if we have the default width amount
			var inputWidth:int = Styles.css.getStyle("." + inputStyleCSS)["width"];
			if(inputWidth == 0){
				inputWidth = Styles.css.getStyle(".formInput")["width"];
			}

			//build the label
			inputLabel = new SimpleTextField("<span class=\"" + labelStyleCSS + "\">" + labelString + LABEL_SEPARATOR + "</span>", 1, true);
			inputLabel.selectable = false;
			
			//setup the text format since Adobe doesn't support CSS styles in input textfields
			var textFormat:TextFormat = new TextFormat();
			
			//font only supports 1 value, so we need to take the first one
			var soloFont:Array = Styles.getCleanValue("." + inputStyleCSS, "fontFamily").split(",");
			textFormat.font = soloFont[0];
			
			//handle the font size
			textFormat.size = Number(Styles.getCleanValue("." + inputStyleCSS, "fontSize"));
			
			//see if it's bold or not
			var isBold:Boolean = false;
			var boldString:String = Styles.css.getStyle("." + inputStyleCSS)["fontWeight"];
			if(boldString != "undefined" && boldString == "bold"){
				isBold = true;
			}
			textFormat.bold = isBold;
			
			//get the colour
			var textColour:uint = Styles.colorToUint("." + inputStyleCSS);
			textFormat.color = textColour;
						
			//make the input box
			inputBox = new TextField();
			inputBox.defaultTextFormat = textFormat
			inputBox.type = TextFieldType.INPUT;
			
			//give a name so the popup won't drag if our mouse is selecting
			inputBox.name = INPUT_NAME;
			inputBox.width = inputWidth;
			inputBox.height = inputBox.textHeight + 4; //default line spacing is 2, but I have to figure out how to find that :D
			inputBox.x = inputLabel.width;
			inputBox.maxChars = maxChars;
			inputBox.tabEnabled = false;
			inputBox.displayAsPassword = isPassword;
			
			//set the selection colour
			//var colourMatrix:Array = [1,0,0,0,0, 0,1,0,0,128, 0,0,1,0,255, 0,0,0,1,0]; 
			//inputBox.filters = [new ColorMatrixFilter(colourMatrix)];
			
			if(restrictInput != ""){
				//only let certain characters in
				inputBox.restrict = restrictInput;
			}
						
			//handle the tab
			if(tabIndex > 0){
				inputBox.tabEnabled = true;
				inputBox.tabIndex = tabIndex;
			}
			
			//multi-row?
			this.rows = rows;
			if(rows > 1){
				createMultiLineInput(inputBox, rows);
			}
			
			//create a background for the input
			inputBoxBackground = createBackground(inputBox);
			
			//move the input & label if there was padding
			inputBox.y = Math.round(inputBoxBackground.height/2 - inputBox.height/2);
			inputLabel.y = inputBox.y;
			
			if(rows > 1){
				//create a scrollbar incase we need it
				scroller = createMultiLineScroller(inputBoxBackground);
				scroller.name = SCROLLER_NAME;
				scroller.visible = false;
				addChild(scroller);
			}
			
			//if the text box needs anything to be there by default
			if(prePopulatedText != ""){
				inputBox.text = prePopulatedText;
				
				//run the change event after it's been added to the stage
				addEventListener(Event.ADDED_TO_STAGE, checkMultiLineInput, false, 0, true);
								
				//adjust the scroller
				if(scroller != null && scroller.visible){
					scroller.y = 0;
				}
			}
			
			if(!isEditable){
				//if you can't edit, transform this to a dynamic text box
				inputBox.type = TextFieldType.DYNAMIC;
				inputBox.selectable = false;
				inputBox.styleSheet = Styles.css;
				inputBox.htmlText = "<span class=\"" + inputDisabledCSS + "\">" + inputBox.text + "</span>";
				
				//remove the BG and border
				//background.visible = false;
			}else{
				//put a listener so we know when it's in focus
				inputBox.addEventListener(FocusEvent.FOCUS_IN, focusIn, false, 0, true);						
				inputBox.addEventListener(FocusEvent.FOCUS_OUT, focusOut, false, 0, true);
			}						
			
			//add everything together
			addChild(inputBoxBackground);
			addChild(inputLabel);
			addChild(inputBox);
		}
		
		private function focusIn(event:FocusEvent):void {
			//change the BG colour
			inputBoxBackground.transform.colorTransform = Styles.colorTransformCSS(Styles.colorToUint(".formInput", "focusColor"), "1");
			
			//disable the backspace
//			if(stage != null){
//				stage.removeEventListener(KeyboardEvent.KEY_DOWN, DeepLinking.checkBackspace);
//			}
		}

		private function focusOut(event:FocusEvent):void {
			inputBoxBackground.transform.colorTransform = new ColorTransform();
			
			//re-enable the backspace
//			if(stage != null){
//				stage.addEventListener(KeyboardEvent.KEY_DOWN, DeepLinking.checkBackspace, false, 0, true);
//			}
		}
		
		
		//this just takes a passed in Input and returns the value
		public function getValue():String {			
			return inputBox.text;
		}
		
		public function changeWidth(newWidth:int):void {
			//this allows you to change the width after it's been built
			inputBox.width = newWidth;
			
			//reset the bg
			removeChild(inputBoxBackground);
			inputBoxBackground = createBackground(inputBox);
			addChildAt(inputBoxBackground, 0);
			
			//move the input & label if there was padding
			inputBox.y = Math.round(inputBoxBackground.height/2 - inputBox.height/2);
			inputLabel.y = inputBox.y;
			
			//if multi-row
			if(rows > 1){
				//kill the old scroller
				removeChild(scroller);
				scroller = createMultiLineScroller(inputBoxBackground);
				scroller.name = SCROLLER_NAME;
				scroller.visible = false;
				addChildAt(scroller, 1);
			}
		}
		
		private function createBackground(input:TextField):Sprite {
			//see if we have any padding
			var padding:int = Styles.css.getStyle("." + inputStyleCSS)["padding"] * 2;
			
			//this will create the background
			var background:Sprite = new Sprite();
			background.graphics.beginFill(Styles.colorToUint("." + inputStyleCSS, "backgroundColor"));
			background.graphics.drawRect(0, 0, input.width, input.height + padding);
			background.graphics.endFill();
			background.x = input.x;
			background.name = BACKGROUND_NAME;
			
			if(Styles.css.getStyle("." + inputStyleCSS)["borderColor"] != undefined){
				var border:Sprite = DrawBorder.create(background, Styles.colorToUint("." + inputStyleCSS, "borderColor"));
				background.addChild(border);
			}
			
			return background;
		}
		
		private function createMultiLineInput(input:TextField, rowCount:uint):void {
			//take a quick snapshot of the width
			var snapWidth:int = input.width;
			
			//set it to multiline and then do a loop to set the right height
			input.multiline = true;
			input.wordWrap = true;
			input.autoSize = TextFieldAutoSize.LEFT;
			
			//loop through the rows to add in the right amount
			var rowLoop:uint = 1;
			while(rowLoop < rowCount){
				input.appendText("\n");
				rowLoop++;
			}
			
			//take a snapshot of the current height
			var snapHeight:int = input.height;
			
			//turn off auto-size and then empty the input
			input.autoSize = TextFieldAutoSize.NONE;
			input.text = "";
			input.height = snapHeight;
			input.width = snapWidth;
			
			//listen for any changes to see if it will need to scroll
			input.addEventListener(Event.CHANGE, checkMultiLineInput, false, 0, true);
		}
		
		private function checkMultiLineInput(event:Event):void {
			if(event.type == Event.ADDED_TO_STAGE){
				//remove the listener
				removeEventListener(Event.ADDED_TO_STAGE, checkMultiLineInput);
				
				//fire the real change
				inputBox.dispatchEvent(new Event(Event.CHANGE));
				return;
			}
			
			var input:TextField = event.currentTarget as TextField;
			//check if we need to scroll
			if(input.maxScrollV > 1){
				if(scroller.height > scroller.startHeight){
					scroller.height = inputBoxBackground.height - input.maxScrollV;
					scroller.y = inputBoxBackground.height - scroller.height;
				}
				scroller.visible = true;
				
				//enable dragging -- using weak incase the window is closed before removed
				scroller.addEventListener(MouseEvent.MOUSE_DOWN, scrollMultiLineInput, false, 0, true);
				input.addEventListener(MouseEvent.MOUSE_WHEEL, wheelMultiLineInput, false, 0, true);
			}else{
				scroller.visible = false;
				
				//disable dragging
				scroller.removeEventListener(MouseEvent.MOUSE_DOWN, scrollMultiLineInput);
				input.removeEventListener(MouseEvent.MOUSE_WHEEL, wheelMultiLineInput);
			}
		}
		
		private function createMultiLineScroller(inputBackground:Sprite):TextScroller {
			var scroll:TextScroller = new TextScroller();
			scroll.x = inputBackground.x + inputBackground.width;
			scroll.y = inputBackground.y;
			scroll.height = inputBackground.height;
			return scroll;
		}
		
		private function scrollMultiLineInput(event:MouseEvent):void {			
			scroller.startDrag(false, new Rectangle(scroller.x, 0, 0, inputBoxBackground.height - scroller.height));
			scroller.stage.addEventListener(MouseEvent.MOUSE_MOVE, scrollMultiLineContent, false, 0, true);
			scroller.stage.addEventListener(MouseEvent.MOUSE_UP, stopScroll, false, 0, true);
		}
		
		private function scrollMultiLineContent(event:MouseEvent):void {			
			if(inputBoxBackground.height - scroller.startHeight < inputBox.maxScrollV){
				inputBox.scrollV = scroller.y * (inputBox.maxScrollV / (inputBoxBackground.height - scroller.startHeight));
			}else{
				inputBox.scrollV = scroller.y;
			}
			
			event.updateAfterEvent();
		}
		
		private function stopScroll(event:MouseEvent):void {
			//kill the listeners and stop the drag
			scroller.stopDrag();
			scroller.stage.removeEventListener(MouseEvent.MOUSE_MOVE, scrollMultiLineContent);
			scroller.stage.removeEventListener(MouseEvent.MOUSE_UP, stopScroll);
		}
		
		private function wheelMultiLineInput(event:MouseEvent):void {
			//make sure the scroll bar doesn't go crazy
			if(scroller.y - event.delta <= inputBox.y){
				scroller.y = inputBox.y;
			}else if(scroller.y - event.delta >= inputBox.y + inputBox.height - scroller.height){
				scroller.y = inputBox.y + inputBox.height - scroller.height;
			}else{
				//Andrea is awesome for helping here.
				scroller.y -= event.delta;
			}
		}

	}
}